package com.yfqy.app.configure.http;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
public class HttpUtils {

    private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    @Autowired
    private CloseableHttpClient httpClient;

    @Autowired
    private RequestConfig requestConfig;

    /**
     * GET 请求
     */
    public String doGet(String url) throws IOException {
        return doGet(url, null);
    }

    /**
     * GET 请求（带请求头）
     */
    public String doGet(String url, Map<String, String> headers) throws IOException {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);

        // 设置请求头
        setHeaders(httpGet, headers);

        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            return handleResponse(response);
        }
    }

    /**
     * POST 请求（表单格式）
     */
    public String doPost(String url, Map<String, String> params) throws IOException {
        return doPost(url, params, null);
    }

    /**
     * POST 请求（表单格式，带请求头）
     */
    public String doPost(String url, Map<String, String> params,
                         Map<String, String> headers) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);

        // 设置请求头
        setHeaders(httpPost, headers);

        // 设置表单参数
        if (params != null && !params.isEmpty()) {
            List<NameValuePair> paramList = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            httpPost.setEntity(new UrlEncodedFormEntity(paramList, StandardCharsets.UTF_8));
        }

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return handleResponse(response);
        }
    }

    /**
     * POST 请求（JSON格式）
     */
    public String doPostJson(String url, String json) throws IOException {
        return doPostJson(url, json, null);
    }

    /**
     * POST 请求（JSON格式，带请求头）
     */
    public String doPostJson(String url, String json, Map<String, String> headers)
            throws IOException {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);

        // 设置请求头
        setHeaders(httpPost, headers);
        httpPost.setHeader("Content-Type", "application/json;charset=utf-8");

        // 设置JSON参数
        if (json != null) {
            StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8);
            httpPost.setEntity(entity);
        }

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return handleResponse(response);
        }
    }

    /**
     * PUT 请求（JSON格式）
     */
    public String doPutJson(String url, String json, Map<String, String> headers)
            throws IOException {
        HttpPut httpPut = new HttpPut(url);
        httpPut.setConfig(requestConfig);

        setHeaders(httpPut, headers);
        httpPut.setHeader("Content-Type", "application/json;charset=utf-8");

        if (json != null) {
            StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8);
            httpPut.setEntity(entity);
        }

        try (CloseableHttpResponse response = httpClient.execute(httpPut)) {
            return handleResponse(response);
        }
    }

    /**
     * DELETE 请求
     */
    public String doDelete(String url, Map<String, String> headers) throws IOException {
        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.setConfig(requestConfig);

        setHeaders(httpDelete, headers);

        try (CloseableHttpResponse response = httpClient.execute(httpDelete)) {
            return handleResponse(response);
        }
    }

    /**
     * 处理响应
     */
    private String handleResponse(CloseableHttpResponse response) throws IOException {
        int statusCode = response.getStatusLine().getStatusCode();
        HttpEntity entity = response.getEntity();
        String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
        EntityUtils.consume(entity); // 确保连接可以被复用

        if (statusCode >= 200 && statusCode < 300) {
            return result;
        } else {
            logger.error("HTTP请求失败，状态码：{}，响应内容：{}", statusCode, result);
            throw new IOException("HTTP请求失败，状态码：" + statusCode);
        }
    }

    /**
     * 设置请求头
     */
    private void setHeaders(HttpRequestBase request, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                request.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 带重试机制的GET请求
     */
    public String doGetWithRetry(String url, Map<String, String> headers, int maxRetries)
            throws IOException {
        IOException lastException = null;

        for (int i = 0; i < maxRetries; i++) {
            try {
                return doGet(url, headers);
            } catch (IOException e) {
                lastException = e;
                logger.warn("第{}次重试失败，URL: {}", i + 1, url, e);
                try {
                    Thread.sleep(1000 * (i + 1)); // 指数退避
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new IOException("重试被中断", ie);
                }
            }
        }

        throw new IOException("重试" + maxRetries + "次后仍然失败", lastException);
    }
}